home *** CD-ROM | disk | FTP | other *** search
/ Netware Super Library / Netware Super Library.iso / drivers / nics / pktdrv7 / ne2000.asm < prev    next >
Encoding:
Assembly Source File  |  1990-07-27  |  36.9 KB  |  1,359 lines

  1. version    equ    3
  2.     page    ,132
  3.     include    defs.asm
  4.  
  5. ;/* PC/FTP Packet Driver source, conforming to version 1.05 of the spec,
  6. ;*  for the NE2000 interface card.
  7. ;*  Robert C Clements, K1BC, 14 February, 1989
  8. ;*  Portions (C) Copyright 1988, 1989 Robert C Clements
  9. ;*  Modified from 3com503 driver by D.J.Horne
  10. ;*
  11. ;  Copyright, 1988, 1989, Russell Nelson
  12.  
  13. ;   This program is free software; you can redistribute it and/or modify
  14. ;   it under the terms of the GNU General Public License as published by
  15. ;   the Free Software Foundation, version 1.
  16. ;
  17. ;   This program is distributed in the hope that it will be useful,
  18. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. ;   GNU General Public License for more details.
  21. ;
  22. ;   You should have received a copy of the GNU General Public License
  23. ;   along with this program; if not, write to the Free Software
  24. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26. ;* Change history:
  27. ;*  Updated to driver spec version 1.08 Feb. 17, 1989 by Russell Nelson.
  28. ;*  Changes 27 Jul 89 by Bob Clements (/Rcc)
  29. ;*    Added Thick versus Thin Ethernet switch  27 Jul 89 by Bob Clements (/Rcc)
  30. ;*    Added call to memory_test.
  31. ;*    Added rcv_mode logic.  Started, but didn't finish, multicast logic. 
  32. ;*      Fixed get_address to return current, not PROM, address.
  33. ;*      Minor races fixed.
  34. ;*  Changes 19 Oct 89, Dave Horne
  35. ;*    Modified for NE2000, use i/o instead of shared memory,
  36. ;*    remove thick/thin logic, remove gate array logic
  37.  
  38. code    segment    word public
  39.     assume    cs:code, ds:code
  40.  
  41. ; Stuff specific to the NE2000 Ethernet controller board
  42. ; WD version in C by Bob Clements, K1BC, May 1988 for the KA9Q TCP/IP package
  43. ; 3Com version based on WD8003E version in .ASM, also by Bob Clements, dated
  44. ;  19 August 1988.  The WD and 3Com cards both use the National DS8390.
  45. ; NE2000 based on 3COM503 version.
  46.  
  47. ; Symbol prefix "EN" is for Ethernet, National chip
  48. ; Symbol prefix "NE" is for NE2000 register(s)
  49.  
  50. ; The EN registers - the DS8390 chip registers
  51. ; These appear at Base+0 through Base+0F
  52. ; There are two (really 3) pages of registers in the chip. You select
  53. ; which page you want, then address them at offsets 00-0F from base.
  54. ; The chip command register (EN_CCMD) appears in both pages.
  55.  
  56. EN_CCMD        equ    000h    ; Chip's command register
  57.  
  58. ; Page 0
  59.  
  60. EN0_STARTPG    equ    001h    ; Starting page of ring bfr
  61. EN0_STOPPG    equ    002h    ; Ending page +1 of ring bfr
  62. EN0_BOUNDARY    equ    003h    ; Boundary page of ring bfr
  63. EN0_TSR        equ    004h    ; Transmit status reg
  64. EN0_TPSR    equ    004h    ; Transmit starting page
  65. EN0_TCNTLO    equ    005h    ; Low  byte of tx byte count
  66. EN0_TCNTHI    equ    006h    ; High byte of tx byte count
  67. EN0_ISR        equ    007h    ; Interrupt status reg
  68. EN0_RSARLO    equ    008h    ; Remote start address reg 0
  69. EN0_RSARHI    equ    009h    ; Remote start address reg 1
  70. EN0_RCNTLO    equ    00ah    ; Remote byte count reg
  71. EN0_RCNTHI    equ    00bh    ; Remote byte count reg
  72. EN0_RXCR    equ    00ch    ; RX control reg
  73. EN0_TXCR    equ    00dh    ; TX control reg
  74. EN0_COUNTER0    equ    00dh    ; Rcv alignment error counter
  75. EN0_DCFG    equ    00eh    ; Data configuration reg
  76. EN0_COUNTER1    equ    00eh    ; Rcv CRC error counter
  77. EN0_IMR        equ    00fh    ; Interrupt mask reg
  78. EN0_COUNTER2    equ    00fh    ; Rcv missed frame error counter
  79.  
  80. ; Page 1
  81.  
  82. EN1_PHYS    equ    001h    ; This board's physical enet addr
  83. EN1_CURPAG    equ    007h    ; Current memory page
  84. EN1_MULT    equ    008h    ; Multicast filter mask array (8 bytes)
  85.  
  86. ; Board regs
  87.  
  88. NE_DATAPORT    equ    10h
  89. NE_OTHERPORT    equ    1fh
  90.  
  91. ; Chip commands in EN_CCMD
  92. ENC_STOP    equ    001h    ; Stop the chip
  93. ENC_START    equ    002h    ; Start the chip
  94. ENC_TRANS    equ    004h    ; Transmit a frame
  95. ENC_RREAD    equ    008h    ; remote read
  96. ENC_RWRITE    equ    010h    ; remote write
  97. ENC_NODMA    equ    020h    ; No remote DMA used on this card
  98. ENC_PAGE0    equ    000h    ; Select page 0 of chip registers
  99. ENC_PAGE1    equ    040h    ; Select page 1 of chip registers
  100.  
  101. ; Commands for RX control reg
  102. ENRXCR_MON    equ    020h    ; Monitor mode (no packets rcvd)
  103. ENRXCR_PROMP    equ    010h    ; Promiscuous physical addresses 
  104. ENRXCR_MULTI    equ    008h    ; Multicast (if pass filter)
  105. ENRXCR_BCST    equ    004h    ; Accept broadcasts
  106. ENRXCR_BAD    equ    003h    ; Accept runts and bad CRC frames
  107.  
  108. ; Commands for TX control reg
  109. ENTXCR_LOOP    equ    002h    ; Set loopback mode
  110.  
  111. ; Bits in EN0_DCFG - Data config register
  112. ENDCFG_BM8    equ    049h    ; Set burst mode, 8 deep FIFO, words
  113.  
  114. ; Bits in EN0_ISR - Interrupt status register
  115. ENISR_RX    equ    001h    ; Receiver, no error
  116. ENISR_TX    equ    002h    ; Transmitter, no error
  117. ENISR_RX_ERR    equ    004h    ; Receiver, with error
  118. ENISR_TX_ERR    equ    008h    ; Transmitter, with error
  119. ENISR_OVER    equ    010h    ; Receiver overwrote the ring
  120. ENISR_COUNTERS    equ    020h    ; Counters need emptying
  121. ENISR_RDC    equ    040h    ; remote dma complete
  122. ENISR_RESET    equ    080h    ; Reset completed
  123. ENISR_ALL    equ    03fh    ; Interrupts we will enable
  124.  
  125. ; Bits in received packet status byte and EN0_RSR
  126. ENPS_RXOK    equ    001h    ; Received a good packet
  127.  
  128. ; Bits in TX status reg
  129.  
  130. ENTSR_PTX    equ    001h    ; Packet transmitted without error
  131. ENTSR_COLL    equ    004h    ; Collided at least once
  132. ENTSR_COLL16    equ    008h    ; Collided 16 times and was dropped
  133. ENTSR_FU    equ    020h    ; TX FIFO Underrun
  134.  
  135. ; Shared memory management parameters
  136.  
  137. XMIT_MTU    equ    600h    ; Largest packet we have room for.
  138. SM_TSTART_PG    equ    040h    ; First page of TX buffer
  139. SM_RSTART_PG    equ    046h    ; Starting page of RX ring
  140. SM_RSTOP_PG    equ    080h    ; Last page +1 of RX ring
  141.  
  142. ; Description of header of each packet in receive area of memory
  143.  
  144. EN_RBUF_STAT    equ    0    ; Received frame status
  145. EN_RBUF_NXT_PG    equ    1    ; Page after this frame
  146. EN_RBUF_SIZE_LO    equ    2    ; Length of this frame
  147. EN_RBUF_SIZE_HI    equ    3    ; Length of this frame
  148. EN_RBUF_NHDR    equ    4    ; Length of above header area
  149.  
  150. ; End of NE2000 parameter definitions
  151.  
  152. pause_    macro
  153.     jmp    $+2
  154. endm
  155.  
  156. longpause macro
  157.     push    cx
  158.     mov    cx,0
  159.     loop    $
  160.     pop    cx
  161. endm
  162.  
  163. ; The following two values may be overridden from the command line.
  164. ; If they are omitted from the command line, these defaults are used.
  165. ; The shared memory base is set by a jumper.  We read it from the
  166. ; card and set up accordingly.
  167.  
  168.     public    int_no, io_addr
  169. int_no        db    2,0,0,0        ; Interrupt level
  170. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  171.  
  172.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  173. driver_class    db    1        ;from the packet spec
  174. driver_type    db    54        ;from the packet spec
  175. driver_name    db    'NE2000',0    ;name of the driver.
  176. driver_function    db    2
  177. parameter_list    label    byte
  178.     db    1    ;major rev of packet driver
  179.     db    9    ;minor rev of packet driver
  180.     db    14    ;length of parameter list
  181.     db    EADDR_LEN    ;length of MAC-layer address
  182.     dw    GIANT    ;MTU, including MAC headers
  183.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  184.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  185.     dw    0    ;(# of successive xmits) - 1
  186. int_num    dw    0    ;Interrupt # to hook for post-EOI
  187.             ;processing, 0 == none,
  188.  
  189. rxcr_bits       db      ENRXCR_BCST     ; Default to ours plus multicast
  190.  
  191.  
  192.     public    card_hw_addr, curr_hw_addr, mcast_list_bits, mcast_all_flag
  193. card_hw_addr    db    0,0,0,0,0,0    ;Physical ethernet address
  194. curr_hw_addr    db    0,0,0,0,0,0    ;Address set into the 8390
  195. mcast_list_bits db      0,0,0,0,0,0,0,0 ;Bit mask from last set_multicast_list
  196. mcast_all_flag  db      0               ;Non-zero if hware should have all
  197.                     ; ones in mask rather than this list.
  198. mcast_sw_filter    db    0        ; set if software filter is required.
  199. is_186        db    0
  200. mcast_sw_fin    dw    0
  201. mcast_sw_fout    dw    0
  202.  
  203.     public    rcv_modes
  204. rcv_modes    dw    7        ;number of receive modes in our table.
  205.         dw    0               ;There is no mode zero
  206.         dw    rcv_mode_1
  207.         dw    rcv_mode_2
  208.         dw    rcv_mode_3
  209.         dw    rcv_mode_4
  210.         dw    rcv_mode_5
  211.         dw    rcv_mode_6
  212.  
  213.     public    mcast_tab
  214. mcast_hcount    dw    0        ; multicast header count
  215. mcast_tab_b    db    0ffh,0ffh,0ffh,0ffh,0ffh,0ffh ; entry for broadcast
  216. mcast_tab    db    (MAX_MULTICAST*EADDR_LEN) dup (0)
  217. ;
  218. ;    a temp buffer for the received header
  219. ;
  220. RCV_HDR_SIZE    equ    18        ; 2 ids @6 + protocol, + 4byte header
  221. rcv_hdr        db    RCV_HDR_SIZE dup(0)
  222.  
  223. ;
  224. ;    The board data
  225. ;
  226.         public    board_data
  227. BOARD_DATA_SIZE equ    32
  228. board_data    db     BOARD_DATA_SIZE dup(0)
  229. soft_tx_errors        dw    0,0
  230. soft_tx_err_bits    db    0
  231. soft_rx_errors        dw    0,0
  232. soft_rx_err_bits    db    0
  233.  
  234.  
  235.  
  236. ; send_pkt: - The Transmit Frame routine
  237.  
  238.     public    as_send_pkt
  239. ; The Asynchronous Transmit Packet routine.
  240. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  241. ;   interrupts possibly enabled.
  242. ; Exit with nc if ok, or else cy if error, dh set to error number.
  243. ;   es:di and interrupt enable flag preserved on exit.
  244. as_send_pkt:
  245.     ret
  246.  
  247.     public    drop_pkt
  248. ; Drop a packet from the queue.
  249. ; Enter with es:di -> iocb.
  250. drop_pkt:
  251.     assume    ds:nothing
  252.     ret
  253.  
  254.     public    xmit
  255. ; Process a transmit interrupt with the least possible latency to achieve
  256. ;   back-to-back packet transmissions.
  257. ; May only use ax and dx.
  258. xmit:
  259.     assume    ds:nothing
  260.     ret
  261.  
  262.  
  263.     public    send_pkt
  264. send_pkt:
  265. ;enter with ds:si -> packet, cx = packet length.
  266. ;exit with nc if ok, or else cy if error, dh set to error number.
  267.     assume    ds:nothing
  268.     loadport        ; Point at chip command register
  269.     setport EN_CCMD        ; ..
  270.     pause_
  271.     mov bx,    8000h        ; Avoid infinite loop
  272. tx_wait:
  273.     in al,    dx        ; Get chip command state
  274.     test al,ENC_TRANS    ; Is transmitter still running?
  275.     jz    tx_idle        ; Go if free
  276.     dec    bx        ; Count the timeout
  277.     jnz    tx_wait        ; Fall thru if TX is stuck
  278.     call    count_out_err    ; Should count these error timeouts
  279.                 ; Maybe need to add recovery logic here
  280. tx_idle:
  281.     cmp    cx,XMIT_MTU    ; Is this packet too large?
  282.     ja    send_pkt_toobig
  283.  
  284.     cmp cx,    RUNT        ; Is the frame long enough?
  285.     jnb    tx_oklen    ; Go if OK
  286.     mov cx,    RUNT        ; Stretch frame to minimum allowed
  287. tx_oklen:
  288.     push    cx        ; Hold count for later
  289.     loadport        ; Set up for address
  290.     setport EN0_ISR
  291.     pause_
  292.     mov    al,ENISR_RDC    ; clear remote interrupt int.
  293.     out    dx,al
  294.     setport    EN0_TCNTLO    ; Low byte of TX count
  295.     pause_
  296.     mov al,    cl        ; Get the count
  297.     out dx,    al        ; Tell card the count
  298.     setport    EN0_TCNTHI    ; High byte of TX count
  299.     pause_
  300.     mov al,    ch        ; Get the count
  301.     out dx,    al        ; Tell card the count
  302.     xor ax,    ax        ; Set up ax at base of tx buffer
  303.     mov ah,    SM_TSTART_PG    ; Where to put tx frame
  304.     pop    cx        ; Get back count to give to board
  305.     call    block_output
  306.     loadport
  307.     mov    cx,0
  308.     setport    EN0_ISR
  309.     in    al,dx
  310. tx_check_rdc:
  311.     test    al,ENISR_RDC    ; dma done ???
  312.     jnz    tx_start
  313.     loop    tx_check_rdc
  314.     jmp    tx_no_rdc
  315. tx_start:
  316.     setport    EN0_TPSR    ; Transmit Page Start Register
  317.     pause_
  318.     mov al,    SM_TSTART_PG
  319.     out dx,    al        ; Start the transmitter
  320.     setport    EN_CCMD        ; Chip command reg
  321.     pause_
  322.     mov al,    ENC_TRANS+ENC_NODMA+ENC_START
  323.     out dx,    al        ; Start the transmitter
  324.     clc            ; Successfully started
  325.     sti
  326.     ret            ; End of transmit-start routine
  327. send_pkt_toobig:
  328.     mov    dh,NO_SPACE
  329.     stc
  330.     sti
  331.     ret
  332. tx_no_rdc:
  333.     mov    dh,CANT_SEND
  334.     stc
  335.     sti
  336.     ret
  337.  
  338. count_soft_err:
  339.     add    word ptr soft_tx_errors,1
  340.     adc    word ptr soft_tx_errors+2,0
  341.     or    byte ptr soft_tx_err_bits,al
  342.     ret
  343.  
  344.     include    movemem.asm
  345.  
  346.  
  347.     public    get_address
  348. get_address:
  349. ;get the address of the interface.
  350. ;enter with es:di -> place to get the address, cx = size of address buffer.
  351. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  352. ; Give caller the one currently in the 8390, not necessarily the one in PROM.
  353.     assume ds:code
  354.     cmp cx,    EADDR_LEN    ; Caller wants a reasonable length?
  355.     jb    get_addr_x    ; No, fail.
  356.     mov cx,    EADDR_LEN    ; Move one ethernet address from our copy
  357.     mov si, offset curr_hw_addr     ; Copy from most recent setting
  358.     rep     movsb
  359.     mov cx,    EADDR_LEN    ; Tell caller how many bytes we fed him
  360.     clc            ; Carry off says success
  361.     ret
  362. get_addr_x:
  363.     stc            ; Tell caller our addr is too big for him
  364.     ret
  365.  
  366. ;
  367. ;get the board data. This is (16) bytes starting at remote
  368. ;dma address 0. Put it in a buffer called board_data.
  369.  
  370. get_board_data:
  371.     mov    cx,10h        ; get 16 bytes,
  372.     push    ds
  373.     pop    es        ; set es to ds
  374.     mov    di,offset board_data
  375.     mov    ax,0        ; from address 0
  376.     call    sp_block_input
  377.     ret
  378.  
  379.     public    set_address
  380. set_address:
  381.     assume    ds:nothing
  382. ;enter with ds:si -> Ethernet address, CX = length of address.
  383. ;exit with nc if okay, or cy, dh=error if any errors.
  384. ;
  385.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  386.     je    set_address_4
  387.     mov    dh,BAD_ADDRESS
  388.     stc
  389.     jmp    short set_address_done
  390. set_address_4:
  391.     push    cs              ; Copy from them to our RAM copy
  392.     pop     es              ; Destination of move
  393.     mov di, offset curr_hw_addr
  394.     rep     movsb           ; Move their address
  395.     call    set_8390_eaddr  ; Put that address in the chip
  396. set_address_okay:
  397.     mov    cx,EADDR_LEN        ;return their address length.
  398.     clc
  399. set_address_done:
  400.     push    cs
  401.     pop    ds
  402.     assume    ds:code
  403.     ret
  404.  
  405. ; Copy our Ethernet address from curr_hw_addr into the DS8390
  406. set_8390_eaddr:
  407.     push    cs              ; Get it from our local RAM copy
  408.     pop     ds
  409.     mov si, offset curr_hw_addr
  410.     mov cx,    EADDR_LEN    ; Move one ethernet address from our copy
  411.     loadport
  412.     setport    EN_CCMD        ; Chip command register
  413.     pause_
  414.     cli            ; Protect from irq changing page bits
  415.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_STOP
  416.     out dx,    al        ; Switch to page one for writing eaddr
  417.     setport    EN1_PHYS    ; Where it goes in 8390
  418.     pause_
  419. set_8390_1:
  420.     lodsb
  421.     out    dx,al
  422.     inc    dx
  423.     loop    set_8390_1
  424.     loadport
  425.     setport    EN_CCMD        ; Chip command register
  426.     pause_
  427.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_STOP
  428.     out dx,    al        ; Restore to page zero
  429.     sti            ; OK for interrupts now
  430.     ret
  431.  
  432. ; Routines to set address filtering modes in the DS8390
  433. rcv_mode_1:     ; Turn off receiver
  434.     mov al,    ENRXCR_MON      ; Set to monitor for counts but accept none
  435.     jmp short rcv_mode_set
  436. rcv_mode_2:     ; Receive only packets to this interface
  437.     mov al, 0               ; Set for only our packets
  438.     jmp short rcv_mode_set
  439. rcv_mode_3:     ; Mode 2 plus broadcast packets (This is the default)
  440.     mov al,    ENRXCR_BCST     ; Set four ours plus broadcasts
  441.     jmp short rcv_mode_set
  442. rcv_mode_4:     ; Mode 3 plus selected multicast packets
  443.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  444.     mov     mcast_all_flag,0    ; need to do sw filter.
  445.     mov    mcast_sw_filter,1    ; because chip filter is not 100%
  446.     jmp short rcv_mode_set
  447. rcv_mode_5:     ; Mode 3 plus ALL multicast packets
  448.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  449.     mov     mcast_all_flag,1
  450.     jmp short rcv_mode_set
  451. rcv_mode_6:     ; Receive all packets (Promiscuous physical plus all multi)
  452.     mov al,    ENRXCR_BCST+ENRXCR_MULTI+ENRXCR_PROMP
  453.     mov     mcast_all_flag,1
  454. rcv_mode_set:
  455.     push    ax              ; Hold mode until masks are right
  456.     call    set_8390_multi  ; Set the multicast mask bits in chip
  457.     pop     ax
  458.     loadport
  459.     setport    EN0_RXCR    ; Set receiver to selected mode
  460.     pause_
  461.     out dx,    al
  462.     mov     rxcr_bits,al    ; Save a copy of what we set it to
  463.     ret
  464.  
  465.  
  466.     public    set_multicast_list
  467. set_multicast_list:
  468. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  469. ;return nc if we set all of them, or cy,dh=error if we didn't.
  470.     assume ds:nothing
  471.     push    cs
  472.     pop    es        ; set es to destination
  473.     mov    di,offset mcast_tab
  474.     mov    ax,cx        ; save byte count
  475.     repz    movsb
  476.     mov    dx,0
  477.     mov    cx,6
  478.     div    cx
  479.     mov    mcast_hcount,ax
  480. ;
  481.     mov    word ptr mcast_list_bits,0
  482.     mov    word ptr mcast_list_bits+2,0
  483.     mov    word ptr mcast_list_bits+4,0
  484.     mov    word ptr mcast_list_bits+6,0
  485. ;
  486.     mov    cx,mcast_hcount
  487.     inc    cx
  488.     mov    di,offset mcast_tab_b
  489. set_mcl_1:
  490.     call    add_mc_bits
  491.     add    di,6
  492.     loop    set_mcl_1
  493.     call    set_8390_multi  ; Set the multicast mask bits in chip
  494.     clc
  495.     mov    dh,0
  496.     ret
  497.  
  498. ;
  499. ;    multicast is at es:di
  500.     assume    ds:nothing
  501. add_mc_bits:
  502.     push    cx
  503.     push    di
  504.     mov    cx,6
  505.     mov    dx,0ffffh            ; this is msw.
  506.     mov    bx,0ffffh            ; set 32 bit number
  507. add_mcb_1:
  508.     mov    al,es:[di]
  509.     inc    di
  510.     call    upd_crc            ; update crc
  511.     loop    add_mcb_1        ; and loop.
  512.     mov    ah,0
  513.     mov    al,dh            ; get ms 8 bits,
  514.     rol    al,1
  515.     rol    al,1
  516.     rol    al,1            ; put 3 bits at bottom
  517.     and    al,7
  518.     mov    dl,al            ; save in dl
  519.     mov    al,dh            ; get ms 8 bits,
  520.     ror    al,1
  521.     ror    al,1            ; but at bottom
  522.     and    al,7
  523.     mov    cl,al            ; save in cl
  524.     mov    al,1
  525.     rol    al,cl            ; set the correct bit,
  526.     mov    di,offset mcast_list_bits
  527.     mov    dh,0
  528.     add    di,dx
  529.     or    cs:[di],al
  530.     pop    di
  531.     pop    cx
  532.     ret
  533.  
  534. ;
  535. ;    dx is high,
  536. ;    bx is low.
  537. ;    al is data
  538.  
  539. upd_crc:
  540.     push    cx
  541.     mov    cx,8        ; do 8 bits
  542.     mov    ah,0
  543. upd_crc1:
  544.     shl    bx,1        ; shift bx
  545.     rcl    dx,1        ; through dx
  546.     rcl    ah,1        ; carry is at bottom of ah
  547.     xor    ah,al        ; xor with lsb of data
  548.     rcr    ah,1        ; and put in carry bit        
  549.     jnc    upd_crc2
  550. ;
  551. ;    autodin is x^32+x^26+x^23x^22+x^16+
  552. ;    x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+1
  553.  
  554.     xor    dx,0000010011000001b
  555.     xor    bx,0001110110110111b
  556. upd_crc2:
  557.     shr    al,1        ; shift the data
  558.     loop    upd_crc1
  559.     pop    cx
  560.     ret
  561.  
  562. ; Set the multicast filter mask bits in case promiscuous rcv wanted
  563. set_8390_multi:
  564.     push    cs
  565.     pop     ds
  566.     assume    ds:code
  567.     loadport
  568.     setport    EN_CCMD        ; Chip command register
  569.     pause_
  570.     mov cx,    8        ; Eight bytes of multicast filter
  571.     mov si, offset mcast_list_bits  ; Where bits are, if not all ones
  572.     cli            ; Protect from irq changing page bits
  573.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_STOP
  574.     out dx,    al        ; Switch to page one for writing eaddr
  575.     setport    EN1_MULT    ; Where it goes in 8390
  576.     pause_
  577.     mov al, mcast_all_flag  ; Want all ones or just selected bits?
  578.     or al,  al
  579.     je      set_mcast_2     ; Just selected ones
  580.     mov al,    0ffh        ; Ones for filter
  581. set_mcast_all:
  582.     out dx,    al        ; Write a mask byte
  583.     inc    dl        ; Step to next one
  584.     loop    set_mcast_all    ; ..    
  585.     jmp short set_mcast_x
  586.  
  587. set_mcast_2:
  588.     lodsb                   ; Get a byte of mask bits
  589.     out dx,    al        ; Write a mask byte
  590.     inc    dl        ; Step to next I/O register
  591.     loop    set_mcast_2     ; ..    
  592. set_mcast_x:
  593.     loadport
  594.     setport    EN_CCMD        ; Chip command register
  595.     pause_
  596.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  597.     out dx,    al        ; Restore to page zero
  598.     sti            ; OK for interrupts now
  599.     ret
  600.  
  601.  
  602.     public    reset_chip
  603.  
  604. reset_chip:
  605.     assume ds:nothing
  606.     loadport        ; Base of I/O regs
  607.     setport    NE_OTHERPORT
  608.     in    al,dx
  609.     longpause
  610.     out    dx,al        ; should set command 21, 80
  611.     longpause
  612.     setport    EN_CCMD        ; Chip command reg
  613.     pause_
  614.     mov al,    ENC_STOP+ENC_NODMA
  615.     out dx,    al        ; Stop the DS8390
  616.     setport EN0_ISR
  617.     pause_
  618.     mov    cx,0
  619. reset_chip_loop:
  620.     in    al,dx        ; get isr
  621.     and    al,ENISR_RESET
  622.     jnz    reset_chip_done
  623.     jmp    reset_chip_loop
  624. reset_chip_done:
  625.     ret
  626.  
  627.     public    terminate
  628. terminate:
  629.     ret
  630.  
  631.     public    reset_interface
  632. reset_interface:
  633.     assume ds:code
  634.     call    reset_chip
  635.     loadport        ; Base of I/O regs
  636.     setport    EN0_ISR        ; Interrupt status reg
  637.     pause_
  638.     mov al,    0ffh        ; Clear all pending interrupts
  639.     out dx,    al        ; ..
  640.     setport    EN0_IMR        ; Interrupt mask reg
  641.     pause_
  642.     xor al,    al        ; Turn off all enables
  643.     out dx,    al        ; ..
  644.     ret
  645.  
  646. ;
  647. ;    Special case Block input routine. Used on extra memory
  648. ;    space for board ID etc. DMA count is set X2,
  649. ;    CX = byte count, es:si = buffer location, ax = buffer address
  650.  
  651. sp_block_input:
  652.     push    ax        ; save buffer address
  653.     loadport
  654.     setport EN_CCMD
  655.     pause_
  656.     mov    al,ENC_NODMA+ENC_STOP
  657.     out    dx,al        ; stop & clear the chip
  658.     setport    EN0_RCNTLO    ; remote byte count 0
  659.     pause_
  660.     mov    ax,cx
  661.     add    ax,ax    
  662.     out    dx,al
  663.     setport    EN0_RCNTHI
  664.     pause_
  665.     mov    al,ah
  666.     out    dx,al
  667.     pop    ax        ; get our page back
  668.     setport    EN0_RSARLO
  669.     pause_
  670.     out    dx,al        ; set as hi address
  671.     setport    EN0_RSARHI
  672.     pause_
  673.     mov    al,ah
  674.     out    dx,al
  675.     setport EN_CCMD
  676.     pause_
  677.     mov    al,ENC_RREAD+ENC_START    ; read and start
  678.     out    dx,al
  679.     setport    NE_DATAPORT
  680.     pause_
  681.     jmp    read_loop
  682. ;
  683. ;    Block input routine
  684. ;    CX = byte count, es:si = buffer location, ax = buffer address
  685.  
  686.     public    block_input
  687. block_input:
  688.     push    ax        ; save buffer address
  689.     loadport
  690.     setport EN_CCMD
  691.     pause_
  692.     mov    al,ENC_NODMA+ENC_PAGE0+ENC_START
  693.     out    dx,al
  694.     setport    EN0_RCNTLO    ; remote byte count 0
  695.     pause_
  696.     mov    al,cl    
  697.     out    dx,al
  698.     setport    EN0_RCNTHI
  699.     pause_
  700.     mov    al,ch
  701.     out    dx,al
  702.     pop    ax        ; get our page back
  703.     setport    EN0_RSARLO
  704.     pause_
  705.     out    dx,al        ; set as hi address
  706.     setport    EN0_RSARHI
  707.     pause_
  708.     mov    al,ah
  709.     out    dx,al
  710.     setport EN_CCMD
  711.     pause_
  712.     mov    al,ENC_RREAD+ENC_START    ; read and start
  713.     out    dx,al
  714.     setport    NE_DATAPORT
  715.     pause_
  716.     cmp    byte ptr is_186,0
  717.     jnz    read_186
  718. read_loop:
  719.     in    al,dx        ; get a byte
  720.     stosb            ; save it
  721.     loop    read_loop
  722.     ret
  723. read_186:
  724.     inc    cx        ; make even
  725.     shr    cx,1        ; word count
  726.     db    0f3h, 06dh    ;masm 4.0 doesn't grok "rep insw"
  727.     ret
  728. ;
  729. ;    Block output routine
  730. ;    CX = byte count, ds:si = buffer location, ax = buffer address
  731.  
  732. block_output:
  733.     assume    ds:nothing
  734.     push    ax        ; save buffer address
  735.     inc    cx        ; make even
  736.     and    cx,0fffeh
  737.     loadport
  738.     setport EN_CCMD
  739.     pause_
  740.     mov    al,ENC_NODMA+ENC_START
  741.     out    dx,al        ; stop & clear the chip
  742.     setport    EN0_RCNTLO    ; remote byte count 0
  743.     pause_
  744.     mov    al,cl    
  745.     out    dx,al
  746.     setport    EN0_RCNTHI
  747.     pause_
  748.     mov    al,ch
  749.     out    dx,al
  750.     pop    ax        ; get our page back
  751.     setport    EN0_RSARLO
  752.     pause_
  753.     out    dx,al        ; set as lo address
  754.     setport    EN0_RSARHI
  755.     pause_
  756.     mov    al,ah
  757.     out    dx,al
  758.     setport EN_CCMD
  759.     pause_
  760.     mov    al,ENC_RWRITE+ENC_START    ; write and start
  761.     out    dx,al
  762.     setport    NE_DATAPORT
  763.     pause_
  764.     cmp    byte ptr is_186,0
  765.     jnz    write_186
  766. write_loop:
  767.     lodsb            ; get a byte
  768.     out    dx,al        ; save it
  769.     loop    write_loop
  770.     ret
  771. write_186:
  772.     shr    cx,1        ; word count
  773.     db    0f3h, 06fh    ;masm 4.0 doesn't grok "rep outsw"
  774.     ret
  775.  
  776.  
  777.  
  778. ; Linkages to non-device-specific routines
  779. ;called when we want to determine what to do with a received packet.
  780. ;enter with cx = packet length, es:di -> packet type.
  781. ;It returns with es:di = 0 if don't want this type or if no buffer available.
  782.     extrn    recv_find: near
  783.  
  784. ;called after we have copied the packet into the buffer.
  785. ;enter with ds:si ->the packet, cx = length of the packet.
  786.     extrn    recv_copy: near
  787.  
  788.     extrn    count_in_err: near
  789.     extrn    count_out_err: near
  790.  
  791.     public    recv
  792. recv:
  793. ;called from the recv isr.  All registers have been saved, and ds=cs.
  794. ;Actually, not just receive, but all interrupts come here.
  795. ;Upon exit, the interrupt will be acknowledged.
  796.  
  797.     assume    ds:code
  798. check_isr:            ; Was there an interrupt from this card?
  799.  
  800.     loadport        ; Point at card's I/O port base
  801.     setport EN0_IMR        ; point at interrupt masks
  802.     pause_            ; switch off, this way we can
  803.     mov    al,0        ; leave the chip running.
  804.     out    dx,al        ; no interrupts please.
  805.     setport    EN0_ISR        ; Point at interrupt status register
  806.     pause_
  807.     in al,    dx        ; Get pending interrupts
  808.     and al,    ENISR_ALL    ; Any?
  809.     jnz    isr_test_overrun
  810.     jmp    interrupt_done    ; Go if none
  811. ; First, a messy procedure for handling the case where the rcvr
  812. ; over-runs its ring buffer.  This is spec'ed by National for the chip.
  813. ; This is handled differently in sample code from 3Com and from WD.
  814. ; This is close to the WD version.  May need tweaking if it doesn't
  815. ; work for the 3Com card.
  816.  
  817. isr_test_overrun: 
  818.     test al,ENISR_OVER    ; Was there an overrun?
  819.     jnz    recv_overrun    ; Go if so.
  820.     jmp    recv_no_overrun    ; Go if not.
  821. recv_overrun:
  822.     setport    EN_CCMD        ; Stop the chip
  823.     pause_
  824.     mov al,    ENC_STOP+ENC_NODMA
  825.     out dx,    al        ; Write "stop" to command register
  826.  
  827.  
  828.     mov al, ENC_NODMA+ENC_PAGE1    ; Could be in previous out, but
  829.     out dx,al        ; was only tested this way
  830.     setport EN1_CURPAG    ; Get current page
  831.     in al,dx
  832.     mov bl,al        ; save it
  833.     setport    EN_CCMD        ;
  834.     mov al, ENC_NODMA+ENC_PAGE0
  835.     out dx,al        ; Back to page 0
  836.  
  837. ; Remove one frame from the ring
  838.     setport    EN0_BOUNDARY    ; Find end of this frame
  839.     pause_
  840.     in al,    dx        ; Get memory page number
  841.     inc    al        ; Page plus 1
  842.     cmp al,    SM_RSTOP_PG    ; Wrapped around ring?
  843.     jnz    rcv_ovr_nwrap    ; Go if not
  844.     mov al,    SM_RSTART_PG    ; Yes, wrap the page pointer
  845. rcv_ovr_nwrap:
  846.  
  847.     cmp    al,bl        ; Check if buffer emptry
  848.     je    rcv_ovr_empty    ; Yes ? Don't receive anything
  849.  
  850.     mov    ah,al        ; make a byte address. e.g. page
  851.     mov    bl,ah        ; and save in bl
  852.     mov    al,0        ; 46h becomes 4600h into buffer
  853.     mov    cx,RCV_HDR_SIZE    ; size of rcv_hdr
  854.     mov    di,offset rcv_hdr ;point to header
  855.     push    ds
  856.     pop    es        ; set es to right place
  857.     call    block_input
  858.     mov al,    rcv_hdr+EN_RBUF_STAT    ; Get the buffer status byte
  859.     test al,ENPS_RXOK    ; Is this frame any good?
  860.     jz    rcv_ovr_ng    ; Skip if not
  861.      call    rcv_frm        ; Yes, go accept it
  862. rcv_ovr_ng:
  863.     mov al,    rcv_hdr+EN_RBUF_NXT_PG    ; Get pointer to next frame
  864.     dec    al        ; Back up one page
  865.     cmp al,    SM_RSTART_PG    ; Did it wrap?
  866.     jge    rcv_ovr_nwr2
  867.     mov al,    SM_RSTOP_PG-1    ; Yes, back to end of ring
  868. rcv_ovr_nwr2:
  869.     loadport        ; Point at boundary reg
  870.     setport    EN0_BOUNDARY    ; ..
  871.     pause_
  872.     out dx,    al        ; Set the boundary
  873. rcv_ovr_empty:
  874.     setport    EN0_RCNTLO    ; Point at byte count regs
  875.     pause_
  876.     xor al,    al        ; Clear them
  877.     out dx,    al        ; ..
  878.     setport    EN0_RCNTHI
  879.     pause_
  880.     out dx,    al
  881.     setport    EN0_ISR        ; Point at status reg
  882.     pause_
  883.     mov cx,    8000h        ; Timeout counter
  884. rcv_ovr_rst_loop:
  885.     in al,    dx        ; Is it finished resetting?
  886.     test al,ENISR_RESET    ; ..
  887.     jnz    rcv_ovr_rst    ; Go if so
  888.     dec    cx        ; Loop til reset, or til timeout
  889.     jnz    rcv_ovr_rst_loop
  890. rcv_ovr_rst:
  891.     loadport        ; Point at Transmit control reg
  892.      setport    EN0_TXCR    ; ..
  893.     pause_
  894.     mov al,    ENTXCR_LOOP    ; Put transmitter in loopback mode
  895.     out dx,    al        ; ..
  896.     setport    EN_CCMD        ; Point at Chip command reg
  897.     pause_
  898.     mov al,    ENC_START+ENC_NODMA
  899.     out dx,    al        ; Start the chip running again
  900.     setport    EN0_TXCR    ; Back to TX control reg
  901.     pause_
  902.     xor al,    al        ; Clear the loopback bit
  903.     out dx,    al        ; ..
  904.     setport    EN0_ISR        ; Point at Interrupt status register
  905.     pause_
  906.     mov al,    ENISR_OVER    ; Clear the overrun interrupt bit
  907.     out dx,    al        ; ..
  908.     call    count_in_err    ; Count the anomaly
  909.      jmp    check_isr    ; Done with the overrun case
  910.  
  911. recv_no_overrun:
  912. ; Handle receive flags, normal and with error (but not overrun).
  913.     test al,ENISR_RX+ENISR_RX_ERR    ; Frame received without overrun?
  914.     jnz    recv_frame    ; Go if so.
  915.     jmp    recv_no_frame    ; Go if not.
  916. recv_frame:
  917.     loadport        ; Point at Chip's Command Reg
  918.      setport    EN_CCMD        ; ..
  919.     pause_
  920.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_START
  921.     out dx,    al        ; Switch to page 1 registers
  922.     setport    EN1_CURPAG    ;Get current page of rcv ring
  923.     pause_
  924.     in al,    dx        ; ..
  925.     mov ah,    al        ; Hold current page in AH
  926.      setport    EN_CCMD        ; Back to page zero registers
  927.     pause_
  928.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  929.     out dx,    al        ; Switch back to page 0 registers
  930.     setport    EN0_BOUNDARY    ;Get boundary page
  931.     pause_
  932.     in al,    dx        ; ..
  933.     inc    al        ; Step boundary from last used page
  934.     cmp al,    SM_RSTOP_PG    ; Wrap if needed
  935.     jne    rx_nwrap3    ; Go if not
  936.     mov al,    SM_RSTART_PG    ; Wrap to first RX page
  937. rx_nwrap3:
  938.     cmp al,    ah        ; Read all the frames?
  939.     je    recv_frame_break    ; Finished them all
  940.  
  941.     mov    ah,al        ; make a byte address. E.G. page
  942.     mov    al,0        ; 46h becomes 4600h into buffer
  943.     mov    bl,ah
  944.     mov    cx,RCV_HDR_SIZE
  945.     mov    di,offset rcv_hdr
  946.     push    ds
  947.     pop    es        ; set es to right place
  948.     call    block_input
  949.     mov al,    rcv_hdr+EN_RBUF_STAT    ; Get the buffer status byte
  950.     test al,ENPS_RXOK    ; Good frame?
  951.     jz    recv_err_no_rcv
  952.     call    rcv_frm        ; Yes, go accept it
  953.     jmp    recv_no_rcv
  954. recv_err_no_rcv:
  955.     or    byte ptr soft_rx_err_bits,al
  956.     add    word ptr soft_rx_errors,1
  957.     adc    word ptr soft_rx_errors+2,0
  958. recv_no_rcv:
  959.     mov al,    rcv_hdr+EN_RBUF_NXT_PG    ; Start of next frame
  960.     dec    al        ; Make previous page for new boundary
  961.     cmp al,    SM_RSTART_PG    ; Wrap around the bottom?
  962.     jge    rcv_nwrap4
  963.     mov al,    SM_RSTOP_PG-1    ; Yes
  964. rcv_nwrap4:
  965.     loadport        ; Point at the Boundary Reg again
  966.      setport    EN0_BOUNDARY    ; ..
  967.     pause_
  968.     out dx,    al        ; Set new boundary
  969.     jmp    recv_frame    ; See if any more frames
  970.  
  971. recv_frame_break:
  972.     loadport        ; Point at Interrupt Status Reg
  973.      setport    EN0_ISR        ; ..
  974.     pause_
  975.     mov al,    ENISR_RX+ENISR_RX_ERR+ENISR_OVER
  976.     out dx,    al        ; Clear those requests
  977.     setport EN_CCMD
  978.     pause_
  979.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  980.     out    dx,al
  981.     jmp    check_isr    ; See if any other interrupts pending
  982.  
  983. recv_no_frame:                ; Handle transmit flags.
  984.     test al,ENISR_TX+ENISR_TX_ERR    ; Frame transmitted?
  985.     jnz    isr_tx        ; Go if so.
  986.     jmp    isr_no_tx    ; Go if not.
  987. isr_tx:
  988.     mov ah,    al        ; Hold interrupt status bits
  989.     loadport        ; Point at Transmit Status Reg
  990.      setport    EN0_TSR        ; ..
  991.     pause_
  992.     in al,    dx        ; ..
  993.     test ah,ENISR_TX    ; Non-error TX?
  994.     jz    isr_tx_err    ; No, do TX error completion
  995.     call    count_soft_err    ; soft error ??
  996.     test al,ENTSR_COLL16    ; Jammed for 16 transmit tries?
  997.     jz    isr_tx_njam    ; Go if not
  998.     call    count_out_err    ; Yes, count those
  999. isr_tx_njam:
  1000.     setport    EN0_ISR        ; Clear the TX complete flag
  1001.     pause_
  1002.     mov al,    ENISR_TX    ; ..
  1003.     out dx,    al        ; ..    
  1004.     jmp    isr_tx_done
  1005. isr_tx_err:
  1006.     test al,ENTSR_FU    ; FIFO Underrun?
  1007.     jz    isr_txerr_nfu
  1008.     call    count_out_err    ; Yes, count those
  1009. isr_txerr_nfu:
  1010.     loadport        ; Clear the TX error completion flag
  1011.     setport    EN0_ISR        ; ..
  1012.     pause_
  1013.     mov al,    ENISR_TX_ERR    ; ..
  1014.     out dx,    al        ; ..    
  1015. isr_tx_done:
  1016. ; If TX queue and/or TX shared memory ring buffer were being
  1017. ; used, logic to step through them would go here.  However,
  1018. ; in this version, we just clear the flags for background to notice.
  1019.  
  1020.      jmp    check_isr    ; See if any other interrupts on
  1021.  
  1022. isr_no_tx:
  1023. ; Now check to see if any counters are getting full
  1024.     test al,ENISR_COUNTERS    ; Interrupt to handle counters?
  1025.     jnz    isr_stat    ; Go if so.
  1026.     jmp    isr_no_stat    ; Go if not.
  1027. isr_stat:
  1028. ; We have to read the counters to clear them and to clear the interrupt.
  1029. ; Version 1 of the PC/FTP driver spec doesn't give us
  1030. ; anything useful to do with the data, though.
  1031. ; Fix this up for V2 one of these days.
  1032.     loadport        ; Point at first counter
  1033.      setport    EN0_COUNTER0    ; ..
  1034.     pause_
  1035.     in al,    dx        ; Read the count, ignore it.
  1036.     setport    EN0_COUNTER1
  1037.     pause_
  1038.     in al,    dx        ; Read the count, ignore it.
  1039.     setport    EN0_COUNTER2
  1040.     pause_
  1041.     in al,    dx        ; Read the count, ignore it.
  1042.     setport    EN0_ISR        ; Clear the statistics completion flag
  1043.     pause_
  1044.     mov al,    ENISR_COUNTERS    ; ..
  1045.     out dx,    al        ; ..
  1046. isr_no_stat:
  1047.      jmp    check_isr    ; Anything else to do?
  1048.  
  1049. interrupt_done:
  1050.     ret
  1051.  
  1052. ; Do the work of copying out a receive frame.
  1053. ; Called with bl/ the page number of the frame header in shared memory
  1054.  
  1055.     public    rcv_frm
  1056. rcv_frm:
  1057. ; first do a software multicast filter.
  1058.     push    bx            ; save page.
  1059.     cmp    mcast_sw_filter,1    ; do software check of mcast ?
  1060.     jnz    rcv_frm_ok        ; no, accept.
  1061.     mov    ax,word ptr rcv_hdr+EN_RBUF_NHDR ; get first word of address
  1062.     test al,1            ; odd first byte
  1063.     jz    rcv_frm_ok        ; must be our address if even
  1064.     inc    word ptr mcast_sw_fin
  1065.  
  1066.     mov    bx,word ptr rcv_hdr+EN_RBUF_NHDR+2 ; get second word of address
  1067.     mov    dx,word ptr rcv_hdr+EN_RBUF_NHDR+4 ; get third word of address
  1068.  
  1069.     mov    di,offset mcast_tab_b    ; point to table and broadcast
  1070.     mov    cx,mcast_hcount        ; get number in table
  1071.     inc    cx            ; plus the broadcast
  1072. rcv_loop:
  1073.     mov    si,di            ; save this table entry
  1074.     cmp    ax,[di]
  1075.     jnz    rcv_trynext
  1076.     inc    di
  1077.     inc    di
  1078.     cmp    bx,[di]
  1079.     jnz    rcv_trynext
  1080.     inc    di
  1081.     inc    di
  1082.     cmp    dx,[di]
  1083.     jz    rcv_mc_ok        ; got it.
  1084. rcv_trynext:
  1085.     mov    di,si            ; get table back,
  1086.     add    di,6
  1087.     loop    rcv_loop
  1088.     pop    bx            ; restore bx
  1089.     jmp    rcv_no_copy
  1090.     
  1091. rcv_mc_ok:
  1092.     inc    word ptr mcast_sw_fout
  1093. rcv_frm_ok:
  1094. ; Set cx to length of this frame.
  1095.     mov ch,    rcv_hdr+EN_RBUF_SIZE_HI    ; Extract size of frame
  1096.     mov cl,    rcv_hdr+EN_RBUF_SIZE_LO    ; Extract size of frame
  1097.     sub cx,    EN_RBUF_NHDR        ; Less the header stuff
  1098. ; Set es:di to point to Ethernet type field.
  1099.     mov di,    offset rcv_hdr+EN_RBUF_NHDR+EADDR_LEN+EADDR_LEN
  1100.     push    cx            ; Save frame size
  1101.     push    es
  1102.     mov ax,    cs            ; Set ds = code
  1103.     mov ds,    ax
  1104.     mov es,ax
  1105.     assume    ds:code
  1106.     call    recv_find        ; See if type and size are wanted
  1107.     pop    ds            ; RX page pointer in ds now
  1108.     assume    ds:nothing
  1109.     pop    cx
  1110.     pop    bx
  1111.     cld            ; Copies below are forward, please
  1112.     mov ax,    es        ; Did recv_find give us a null pointer?
  1113.     or ax,    di        ; ..
  1114.     je    rcv_no_copy    ; If null, don't copy the data    
  1115.  
  1116.     push    cx        ; We will want the count and pointer
  1117.     push    es        ;  to hand to client after copying,
  1118.     push    di        ;  so save them at this point
  1119.     mov    ah,bl        ; set ax to page to start from
  1120.     mov    al,EN_RBUF_NHDR    ; skip the header stuff
  1121.     call    block_input
  1122.     pop    si        ; Recover pointer to destination
  1123.     pop    ds        ; Tell client it's his source
  1124.     pop    cx        ; And it's this long
  1125.     assume    ds:nothing
  1126.     call    recv_copy    ; Give it to him
  1127. rcv_no_copy:
  1128.     push    cs        ; Put ds back in code space
  1129.     pop    ds        ; ..
  1130.     assume    ds:code
  1131.     ret            ; That's it for rcv_frm
  1132.  
  1133.  
  1134.     public    recv_exiting
  1135. recv_exiting:
  1136. ;called from the recv isr after interrupts have been acknowledged.
  1137. ;Only ds and ax have been saved.
  1138.     assume    ds:nothing
  1139.     push    dx
  1140.     loadport
  1141.     setport    EN0_IMR        ; Tell card it can cause these interrupts
  1142.     pause_
  1143.     mov al,    ENISR_ALL
  1144.     out dx,    al
  1145.     pop    dx
  1146.     ret
  1147.  
  1148.  
  1149. ;any code after this will not be kept after initialization.
  1150. end_resident    label    byte
  1151.  
  1152.  
  1153.     public    usage_msg
  1154. usage_msg    db    "usage: NE2000 [-n] [-d] [-w] <packet_int_no> <int_level> <io_addr>",CR,LF,'$'
  1155.  
  1156.     public    copyright_msg
  1157. copyright_msg    db    "Packet driver for Novell NE2000, version ",'0'+majver,".",'0'+version,CR,LF
  1158.         db    "Portions Copyright 1989, Robert C. Clements, K1BC",CR,LF,'$'
  1159.  
  1160. cfg_err_msg:
  1161.     db    "NE2000 Configuration failed. Check parameters.",CR,LF,'$'
  1162. int_no_name:
  1163.     db    "Interrupt number ",'$'
  1164. io_addr_name:
  1165.     db    "I/O port ",'$'
  1166. using_186_msg    db    "Using 80[123]86 I/O instructions.",CR,LF,'$'
  1167.  
  1168.     extrn    set_recv_isr: near
  1169.  
  1170. ;enter with si -> argument string, di -> word to store.
  1171. ;if there is no number, don't change the number.
  1172.     extrn    get_number: near
  1173.  
  1174. ;enter with dx -> name of word, di -> dword to print.
  1175.     extrn    print_number: near
  1176.  
  1177.     public    parse_args
  1178. parse_args:
  1179. ;exit with nc if all went well, cy otherwise.
  1180.     mov di,    offset int_no        ; May override interrupt channel
  1181.     call    get_number
  1182.     mov di,    offset io_addr        ; May override I/O address
  1183.     call    get_number
  1184. ;    mov di,    offset mem_base        ; Not movable in 3C503
  1185. ;    call    get_number        ; Must get from jumpers.
  1186.     clc
  1187.     ret
  1188.  
  1189.  
  1190. cfg_error:
  1191.     mov    dx,offset cfg_err_msg
  1192. error:
  1193.     mov    ah,9        ; Type the msg
  1194.     int    21h
  1195.     stc            ; Indicate error
  1196.     ret            ; Return to common code
  1197.  
  1198. ; Called once to initialize the NE2000 card
  1199.  
  1200.     public    etopen
  1201. etopen:                ; Initialize interface
  1202.  
  1203. ;Determine the processor type.  The 8088 and 8086 will actually shift ax
  1204. ;over by 33 bits, while the 80[123]86 use a shift count mod 32.
  1205. ;This bit lifted from NI5010 driver.
  1206.  
  1207.     mov    cl,33
  1208.     mov    ax,0ffffh
  1209.     shl    ax,cl
  1210.     jz    not_186
  1211.     mov    is_186,1
  1212.     mov    dx,offset using_186_msg
  1213.     mov    ah,9
  1214.     int    21h
  1215. not_186:
  1216.  
  1217. ; Now, initialize the DS8390 Ethernet Controller chip
  1218. ini_8390:
  1219.     call    reset_chip
  1220.     loadport
  1221.     setport    EN0_DCFG    ; Configure the fifo organization
  1222.     pause_
  1223.     mov al,    ENDCFG_BM8    ; Fifo threshold = 8 bytes
  1224.     out dx,    al
  1225.     setport    EN_CCMD        ; DS8390 chip's command register
  1226.     pause_
  1227.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_STOP
  1228.     out dx,    al        ; Switch to page zero
  1229.  
  1230.     setport    EN0_TXCR    ; Set transmitter mode to normal
  1231.     pause_
  1232.     xor al,    al
  1233.     out dx,    al
  1234.     setport    EN0_RXCR    ; Set receiver to monitor mode
  1235.     pause_
  1236.     mov al,    ENRXCR_MON
  1237.     out dx,    al
  1238.  
  1239.  
  1240. ; Set up control of shared memory, buffer ring, etc.
  1241.  
  1242.     setport    EN0_STARTPG    ; Set receiver's first buffer page
  1243.     pause_
  1244.     mov al,    SM_RSTART_PG
  1245.     out dx,    al
  1246.  
  1247.     setport    EN0_STOPPG    ;  and receiver's last buffer page + 1
  1248.     pause_
  1249.     mov al,    SM_RSTOP_PG
  1250.     out dx,    al
  1251.  
  1252.     setport    EN0_BOUNDARY    ; Set initial "last page we have emptied"
  1253.     pause_
  1254.     mov al,    SM_RSTOP_PG    ; (WD doc says set to RSTART_PG)
  1255.     dec    al        ; (3Com doc says set to RSTOP_PG-1 ?)
  1256. ;                ; (and 3Com handling of BOUNDARY is
  1257. ;                ;  different throughout.)
  1258.     out dx,    al        ; (Check out why WD and 3Com disagree)
  1259. ;
  1260.  
  1261.     setport    EN0_IMR        ; Clear all interrupt enable flags
  1262.     pause_
  1263.     xor al,    al
  1264.     out dx,    al
  1265.  
  1266.     setport    EN0_ISR        ; Clear all interrupt assertion flags
  1267.     pause_
  1268.     mov al,    0ffh
  1269.     out dx,    al
  1270.  
  1271.     setport    EN_CCMD
  1272.     pause_
  1273.     mov al,    ENC_NODMA+ENC_PAGE1+ENC_STOP
  1274.     out    dx,al
  1275.     
  1276.     setport    EN1_CURPAG
  1277.     pause_
  1278.     mov al,    SM_RSTART_PG
  1279.     out dx,    al
  1280.     
  1281.     setport    EN_CCMD
  1282.     pause_
  1283.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_START
  1284.     out    dx,al
  1285.     
  1286.     call    get_board_data    ; read board data
  1287.  
  1288.     push    ds              ; Copy from card's address to current address
  1289.     pop     es
  1290.  
  1291.     mov si, offset board_data    ; address is at start
  1292.     mov di, offset curr_hw_addr
  1293.     mov cx, EADDR_LEN       ; Copy one address length
  1294.     rep     movsb           ; ..
  1295.     call    set_8390_eaddr  ; Now set the address in the 8390 chip
  1296.     call    set_8390_multi  ; Put the right stuff into 8390's multicast masks
  1297.     loadport        ; Base of I/O regs
  1298.     setport    EN_CCMD        ; Chip command register
  1299.     pause_
  1300.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_STOP
  1301.     out dx,    al        ; Back to page zero
  1302.     setport    EN0_RCNTLO    ; Clear the byte count registers
  1303.     pause_
  1304.     xor al,    al        ; ..
  1305.     out dx,    al
  1306.     setport    EN0_RCNTHI
  1307.     pause_
  1308.     out dx,    al        ; Clear high byte, too
  1309.     setport    EN0_IMR        ; Clear all interrupt enable flags
  1310.     pause_
  1311.     xor al,    al
  1312.     out dx,    al
  1313.     setport    EN0_ISR        ; Clear all interrupt assertion flags
  1314.     pause_
  1315.     mov al,    0ffh        ; again for safety before making the
  1316.     out dx,    al        ; interrupt be enabled
  1317.     call    set_recv_isr    ; Put ourselves in interrupt chain
  1318.     loadport
  1319.     setport    EN_CCMD        ; Now start the DS8390
  1320.     pause_
  1321.     mov al,    ENC_START+ENC_NODMA
  1322.     out dx,    al        ; interrupt be enabled
  1323.     setport    EN0_RXCR    ; Tell it what frames to accept
  1324.     pause_
  1325.     mov al,    rxcr_bits       ; As most recently set by set_mode
  1326.     out dx,    al
  1327.     setport    EN0_IMR        ; Tell card it can cause these interrupts
  1328.     pause_
  1329.     mov al,    ENISR_ALL
  1330.     out dx,    al
  1331.  
  1332.     mov    al, int_no        ; Get board's interrupt vector
  1333.     add    al, 8
  1334.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  1335.     jb    set_int_num        ; No.
  1336.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  1337. set_int_num:
  1338.     xor    ah, ah            ; Clear high byte
  1339.     mov    int_num, ax        ; Set parameter_list int num.
  1340.  
  1341.     mov dx,    offset end_resident    ; Report our size
  1342.     clc                ; Say no error
  1343.     ret                ; Back to common code
  1344.  
  1345.     public    print_parameters
  1346. print_parameters:
  1347. ;echo our command-line parameters
  1348.     mov    di,offset int_no    ; May override interrupt channel
  1349.     mov    dx,offset int_no_name    ; Message for it
  1350.     call    print_number
  1351.     mov    di,offset io_addr    ; May override I/O address
  1352.     mov    dx,offset io_addr_name    ; Message for it
  1353.     call    print_number
  1354.     ret
  1355.  
  1356. code    ends
  1357.  
  1358.     end
  1359.